#include "data.hpp"
#include </home/lml/cpp-httplib/httplib.h>

namespace aod{
#define WWWROOT "./www" //静态资源根目录
#define VIDEO_ROOT "/video/"
#define IMAGE_ROOT "/image/"
    //因为httplib基于多线程，因此数据管理对象需要在多线程中访问，为了便于访问定义全局变量
    TableVideo* tb_video = NULL;
     //这里为了更加功能模块划分清晰一些，不使用lamda表达式完成，否则所有的功能实现集中到一个函数中太过庞大
    class Server{
        private:
            int _port;//服务器的 监听端口
            httplib::Server _srv;//用于搭建http服务器
        private:
            //对应的业务处理接口
            static void Insert(const httplib::Request &req,httplib::Response &rsp)
            {
                if(req.has_file("name")==false ||
                req.has_file("info")==false ||
                req.has_file("video")==false ||
                req.has_file("image")==false ){
                    rsp.status = 400;
                    rsp.body = R"({"result":false,"reason":"上传的数据信息错误"})";
                    rsp.set_header("Content-Type","application/json");
                    return ; 
                }
                //MultipartFormData 4个string成员{name 字段名，content 文件的数据，filename 文件名称，content_type 正文类型}
                httplib::MultipartFormData name = req.get_file_value("name");//视频名称
                httplib::MultipartFormData info = req.get_file_value("info");//视频简介
                httplib::MultipartFormData video = req.get_file_value("video");//视频文件
                httplib::MultipartFormData image = req.get_file_value("image");//图片文件

                std::string video_name = name.content;
                std::string video_info = info.content;
                // ./www/image/发发t.jpg
                std::string wroot=WWWROOT;
                std::string video_path = wroot + VIDEO_ROOT + video_name + video.filename;
                std::string image_path = wroot + IMAGE_ROOT + video_info + image.filename;

                //文件的存储
                if(FileUtil(video_path).SetContent(video.content)==false){
                    rsp.status = 501;
                    rsp.body = R"({"result":false,"reason":"视频文件存储失败"})";
                    rsp.set_header("Content-Type","application/json");
                    return ;
                }
                if(FileUtil(image_path).SetContent(image.content)==false){
                    rsp.status = 502;
                    rsp.body = R"({"result":false,"reason":"视频图片存储失败"})";
                    rsp.set_header("Content-Type","application/json");
                    return ;
                }
                Json::Value video_json;
                video_json["name"] = video_name;
                video_json["info"] = video_info;
                video_json["video"] = VIDEO_ROOT + video_name + video.filename;
                video_json["image"] = IMAGE_ROOT + video_info + image.filename; // /image/发发t.jpg
                if(tb_video->Insert(video_json)==false){
                    rsp.status = 503;
                    rsp.body = R"({"result":false,"reason":"数据库新增数据失败"})";
                    rsp.set_header("Content-Type","application/json");
                    return ;
                }
                return ;
            }
            static void Delete(const httplib::Request &req,httplib::Response &rsp)
            {
                //1. 获取要删除的视频id
                //matches:存放正则表达式匹配的规则数据 /numbers/123 matches[0]="/numbers/123,matches[1]="123"
                int video_id = std::stoi(req.matches[1]);
                //2. 删除视频和图片文件
                Json::Value video;
                if(tb_video->SelectOne(video_id,&video)==false){
                    rsp.status = 504;
                    rsp.body = R"({"result":false,"reason":"不存在的视频信息"})";
                    rsp.set_header("Content-Type","application/json");
                    return ;
                }
                std::string root = WWWROOT;
                std::string video_path = root + video["video"].asString();
                std::string image_path = root + video["image"].asString();
                remove(video_path.c_str());//Bug ? 
                remove(image_path.c_str());
                //3. 删除数据库信息 
                if(tb_video->Delete(video_id)==false){
                    rsp.status = 505;
                    rsp.body = R"({"result":false,"reason":"删除数据库信息失败"})";
                    rsp.set_header("Content-Type","application/json");
                    return ;
                }
                return ;
            }
            static void Update(const httplib::Request &req,httplib::Response &rsp)
            {
                //1. 获取要修改的视频信息 1. 视频id 2. 修改后的信息
                int video_id = std::stoi(req.matches[1]);
                Json::Value video;
                if(JsonUtil::UnSerialize(req.body,&video)==false){
                    rsp.status = 400;
                    rsp.body = R"({"result":false,"reason":"新的视频信息格式解析失败"})";
                    rsp.set_header("Content-Type","application/json");
                    return ;
                }
                //2. 修改数据库数据
                if(tb_video->Update(video_id,video)==false){
                    rsp.status = 506;
                    rsp.body = R"({"result":false,"reason":"修改数据库信息失败"})";
                    rsp.set_header("Content-Type","application/json");
                    return ;
                }
                return ;
            }
            static void SelectOne(const httplib::Request &req,httplib::Response &rsp)
            {
                //1. 获取视频的id
                int video_id = std::stoi(req.matches[1]);
                //2. 在数据库中查询指定视频信息
                Json::Value video;
                if(tb_video->SelectOne(video_id,&video)==false){
                    rsp.status = 507;
                    rsp.body = R"({"result":false,"reason":"查询数据库指定信息失败"})";
                    rsp.set_header("Content-Type","application/json");
                    return ;
                }
                //3. 组织响应正文 -- json格式的字符串
                JsonUtil::Serialize(video,&rsp.body);
                rsp.set_header("Content-Type","application/json");
                return ;
            }
            static void SelectAll(const httplib::Request &req,httplib::Response &rsp)
            {
                // /video &  /video?search="关键字"     看是哪种查询
                bool select_flag = true;//默认所有查询
                std::string search_key;
                if(req.has_param("search")==true){
                    select_flag = false;//模糊匹配
                    search_key = req.get_param_value("search");
                }
                Json::Value videos;
                if(select_flag == true)
                {
                    if(tb_video->SelectAll(&videos)==false){
                        rsp.status = 508;
                        rsp.body = R"({"result":false,"reason":"查询所有数据库信息失败"})";
                        rsp.set_header("Content-Type","application/json");
                        return ;
                    }
                }
                else
                {
                    if(tb_video->SelectLike(search_key,&videos)==false){
                        rsp.status = 509;
                        rsp.body = R"({"result":false,"reason":"查询匹配数据库信息失败"})";
                        rsp.set_header("Content-Type","application/json");
                        return ;
                    }
                }
                //3. 组织响应正文 -- json格式的字符串
                JsonUtil::Serialize(videos,&rsp.body);
                rsp.set_header("Content-Type","application/json");
                return ;     
            }
        public:
            Server(int port):_port(port){}
            bool RunMoudule()//建立请求与处理函数的映射关系，设置静态资源根目录，启动服务器
            {
                //1. 初始化操作--初始化数据管理模块，创建指定的目录
                tb_video = new TableVideo(); //data.hpp里面是没有初始化TableVideo对象的！
                FileUtil(WWWROOT).CreateDirectory();
                std::string wroot = WWWROOT;
                std::string video_real_path = wroot + VIDEO_ROOT;
                FileUtil(video_real_path).CreateDirectory();
                std::string image_real_path = wroot + IMAGE_ROOT;
                FileUtil(image_real_path).CreateDirectory();
                //2. 搭建http服务器，开始运行
                //2.1设置静态资源根目录
                _srv.set_mount_point("/",WWWROOT);//即设置"/"就是WWWWROOT
                //2.2添加请求-处理函数映射关系
                _srv.Post("/video",Insert);
                _srv.Delete("/video/(\\d+)",Delete);
                _srv.Put("/video/(\\d+)",Update);
                _srv.Get("/video/(\\d+)",SelectOne);
                _srv.Get("/video",SelectAll);
                //正则表达式中 ，\d表示数字，+表示匹配前面的字符一次或者多次，（）表示单独捕捉数据
                //3. 启动服务器
                _srv.listen("0.0.0.0",_port);
                return true;
                /*程序进来之后，先初始化数据管理模块，然后创建该创建的目录，然后设置静态资源根目录，
                然后添加请求与处理函数的对应关系，最后启动服务器。
                httplib在收到请求之后首先查看请求的方法以及资源路径，看映射关系里面有没有对应的函数去
                处理，如果有就直接调用，如果没有再查看请求的是否是一个静态资源（查看WWWROOT里面有没有
                对应的文件，如果有就进行响应，如果没有就返回404）
                而我们需要做的就是对应的业务处理过程（就是这些对应的函数）*/
            }
    };
}